home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / asm / adisv1_3.lha / src / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-24  |  16.7 KB  |  739 lines

  1. /*
  2.  * Change history
  3.  * $Log:    util.c,v $
  4.  * Revision 3.0  93/09/24  17:54:29  Martin_Apel
  5.  * New feature: Added extra 68040 FPU opcodes
  6.  * 
  7.  * Revision 2.3  93/07/18  22:56:58  Martin_Apel
  8.  * *** empty log message ***
  9.  * 
  10.  * Revision 2.2  93/07/10  13:02:35  Martin_Apel
  11.  * Major mod.: Added full jump table support. Seems to work quite well
  12.  * 
  13.  * Revision 2.1  93/07/08  22:29:31  Martin_Apel
  14.  * 
  15.  * Minor mod.: Displacements below 4 used with pc indirect indexed are
  16.  *             not entered into the symbol table anymore
  17.  * 
  18.  * Revision 2.0  93/07/01  11:54:56  Martin_Apel
  19.  * *** empty log message ***
  20.  * 
  21.  * Revision 1.17  93/07/01  11:45:00  Martin_Apel
  22.  * Minor mod.: Removed $-sign from labels
  23.  * Minor mod.: Prepared for tabs instead of spaces
  24.  * 
  25.  * Revision 1.16  93/06/16  20:31:31  Martin_Apel
  26.  * Minor mod.: Removed #ifdef FPU_VERSION and #ifdef MACHINE68020
  27.  * 
  28.  * Revision 1.15  93/06/04  11:56:35  Martin_Apel
  29.  * New feature: Added -ln option for generation of ascending label numbers
  30.  * 
  31.  * Revision 1.14  93/06/03  20:30:17  Martin_Apel
  32.  * Minor mod.: Additional linefeed generation for end instructions has been
  33.  *             moved to format_line
  34.  * New feature: Added -a switch to generate comments for file offsets
  35.  * 
  36.  * Revision 1.13  93/05/27  20:50:48  Martin_Apel
  37.  * Bug fix: Register list was misinterpreted for MOVEM / FMOVEM
  38.  *          instructions.
  39.  * 
  40.  */
  41.  
  42. #include <exec/types.h>
  43. #include <string.h>
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include "defs.h"
  47. #include "string_recog.h"
  48.  
  49. static char rcsid [] =  "$Id: util.c,v 3.0 93/09/24 17:54:29 Martin_Apel Exp $";
  50.  
  51. /**********************************************************************/
  52. /*      A few routines doing string handling such as formatting       */
  53. /*        a hex value, formatting the register list for MOVEM         */
  54. /*              instructions, different address modes...              */
  55. /*        sprintf would have been much easier but sloooow !!!         */
  56. /**********************************************************************/
  57.  
  58. PRIVATE char hex_chars [] = "0123456789ABCDEF";
  59.  
  60. /**************************************************************************/
  61.  
  62. char *format_d (char *where, short val, BOOL sign)
  63.  
  64. {
  65. char stack [10],
  66.      *sp;
  67. register ULONG my_val;
  68.  
  69. if (val < 0 && sign)
  70.   {
  71.   my_val = ((ULONG) -val) & 0xffff;
  72.   *where++ = '-';
  73.   }
  74. else
  75.   my_val = (ULONG) val & 0xffff;
  76.  
  77. sp = stack;
  78. while (my_val != 0)
  79.   {
  80.   *sp++ = my_val & 0xf;          /* MOD 16 */
  81.   my_val = my_val >> 4;          /* DIV 16 */
  82.   }
  83.  
  84. *where++ = '$';
  85. if (sp == stack)
  86.   /* value is zero */
  87.   *where++ = '0';
  88. else
  89.   {
  90.   do
  91.     *where++ = hex_chars [*(--sp)];
  92.   while (sp != stack);
  93.   }
  94. *where = 0;
  95. return (where);
  96. }
  97.  
  98. /**************************************************************************/
  99.  
  100. char *format_ld  (char *where, long val, BOOL sign)
  101.  
  102. {
  103. char stack [15],
  104.      *sp;
  105. register ULONG my_val;
  106.  
  107. if (val < 0 && sign)
  108.   {
  109.   my_val = (ULONG) -val;
  110.   *where++ = '-';
  111.   }
  112. else
  113.   my_val = (ULONG) val;
  114.  
  115. sp = stack;
  116. while (my_val != 0)
  117.   {
  118.   *sp++ = my_val & 0xf;          /* MOD 16 */
  119.   my_val = my_val >> 4;          /* DIV 16 */
  120.   }
  121.  
  122.  
  123. *where++ = '$';
  124. if (sp == stack)
  125.   /* value is zero */
  126.   *where++ = '0';
  127. else
  128.   {
  129.   do
  130.     *where++ = hex_chars [*(--sp)];
  131.   while (sp != stack);
  132.   }
  133. *where = 0;
  134. return (where);
  135. }
  136.  
  137. /**************************************************************************/
  138.  
  139. char *format_ld_no_dollars  (char *where, long val, BOOL sign)
  140.  
  141. /* The same as format_ld but without the dollar sign */
  142.  
  143. {
  144. char stack [15],
  145.      *sp;
  146. register ULONG my_val;
  147.  
  148. if (val < 0 && sign)
  149.   {
  150.   my_val = (ULONG) -val;
  151.   *where++ = '-';
  152.   }
  153. else
  154.   my_val = (ULONG) val;
  155.  
  156. sp = stack;
  157. while (my_val != 0)
  158.   {
  159.   *sp++ = my_val & 0xf;          /* MOD 16 */
  160.   my_val = my_val >> 4;          /* DIV 16 */
  161.   }
  162.  
  163.  
  164. if (sp == stack)
  165.   /* value is zero */
  166.   *where++ = '0';
  167. else
  168.   {
  169.   do
  170.     *where++ = hex_chars [*(--sp)];
  171.   while (sp != stack);
  172.   }
  173. *where = 0;
  174. return (where);
  175. }
  176.  
  177. /**************************************************************************/
  178.  
  179. void format_reg_list (char *where, unsigned short list, BOOL incr_list,
  180.                       short reglist_offset)
  181.  
  182. {
  183. register int i;
  184. register long mylist;                 /* list in order a7-a0/d7-d0 */
  185. short last_set;
  186. BOOL regs_used;
  187.  
  188. if (!incr_list)
  189.   {
  190.   mylist = 0;
  191.   for (i = 0; i < 16; i++)
  192.     {
  193.     if (list & (1 << i))
  194.       mylist |= 1 << (15 - i);
  195.     }
  196.   }
  197. else
  198.   mylist = list;
  199.  
  200. last_set = -1;
  201. regs_used = FALSE;
  202. for (i = 0; i < 17; i++)
  203.   {
  204.   if ((mylist & (1 << i)) && last_set == -1)
  205.     {
  206.     if (regs_used)
  207.       strcat (where, "/");
  208.     strcat (where, reg_names [i + reglist_offset]);
  209.     last_set = i;
  210.     regs_used = TRUE;
  211.     }
  212.   else if (!(mylist & (1 << i)))
  213.     {
  214.     if (last_set == i - 1)
  215.       last_set = -1;
  216.     else if (last_set != -1)
  217.       {
  218.       strcat (where, "-");
  219.       strcat (where, reg_names [i - 1 + reglist_offset]);
  220.       last_set = -1;
  221.       }
  222.     }
  223.   if (i == 7 && (mylist & 0x180) == 0x180)
  224.     {
  225.     if (last_set != 7) 
  226.       /* d7 and a0 both used and still in a list */
  227.       {
  228.       strcat (where, "-");
  229.       strcat (where, reg_names [7 + reglist_offset]);
  230.       }
  231.     last_set = -1;
  232.     }      
  233.   }
  234. }
  235.  
  236. /**************************************************************************/
  237.  
  238. char *immed (char *to, long val)
  239.  
  240. {
  241. /* e.g. #$17 */
  242.  
  243. *to++ = '#';
  244. return (format_ld (to, val, FALSE));
  245. }
  246.  
  247. /**************************************************************************/
  248.  
  249. void pre_dec (char *to, short reg_num)
  250.  
  251. {
  252. /* e.g. -(A1) */
  253.  
  254. PRIVATE char *template = "-(  )";
  255.  
  256. strcpy (to, template);
  257. strcpy (to + 2, reg_names [reg_num]);
  258. *(to + 4) = ')';
  259. }
  260.  
  261. /**************************************************************************/
  262.  
  263. void post_inc (char *to, short reg_num)
  264.  
  265. {
  266. /* e.g. (A2)+ */
  267.  
  268. PRIVATE char *template = "(  )+";
  269.  
  270. strcpy (to, template);
  271. strcpy (to + 1, reg_names [reg_num]);
  272. *(to + 3) = ')';
  273. }
  274.  
  275. /**************************************************************************/
  276.  
  277. void indirect (char *to, short reg_num)
  278.  
  279. {
  280. /* e.g. (A1) */
  281.  
  282. *to++ = '(';
  283. *to++ = *(reg_names [reg_num]);
  284. *to++ = *(reg_names [reg_num] + 1);
  285. *to++ = ')';
  286. *to = 0;
  287. }
  288.  
  289. /**************************************************************************/
  290.  
  291. void disp_an (char *to, short reg_num, short disp)
  292.  
  293. {
  294. /* e.g. 4(A0) */
  295.  
  296. to = format_d (to, disp, TRUE);
  297. *to++ = '(';
  298. *to++ = *(reg_names [reg_num]);
  299. *to++ = *(reg_names [reg_num] + 1);
  300. *to++ = ')';
  301. *to = 0;
  302. }
  303.  
  304. /**************************************************************************/
  305.  
  306. void disp_an_indexed (char *to, short an, char disp, short index_reg, 
  307.                       short scale, short size)
  308.  
  309. {
  310. /* e.g. 4(A0,D0.W*4) */
  311.  
  312. PRIVATE char *template = "(  ,  .W* )";
  313.  
  314. if (an == PC && !((*code & 0xffc0) == 0x4ec0))
  315.   {
  316.   /* Don't generate label for JMP instruction */
  317.   gen_label (to, current_address + 2 + disp, TRUE);
  318.   while (*(++to));
  319.   }
  320. else
  321.   to = format_d (to, (short)disp, TRUE);
  322. strcpy (to, template);
  323. strcpy (to + 1, reg_names [an]);
  324. *(to + 3) = ',';
  325. strcpy (to + 4, reg_names [index_reg]);
  326. *(to + 6) = '.';
  327. if (size == ACC_LONG)
  328.   *(to + 7) = 'L';
  329. if (scale == 1)
  330.   {
  331.   *(to + 8) = ')';
  332.   *(to + 9) = 0;
  333.   }
  334. else
  335.   *(to + 9) = scale + '0';
  336. }
  337.  
  338. /**************************************************************************/
  339.  
  340. int full_extension (char *to, UWORD *extension, short mode, short reg)
  341.  
  342. {
  343. /* Who did come up with these complicated addressing modes ? */
  344. /* Does anybody ever use them ? */
  345.  
  346. short base_disp_size,
  347.       outer_disp_size;
  348. char index_reg [10],
  349.      base_reg [10],
  350.      base_disp [80],
  351.      outer_disp [15],
  352.      tmp_string [10];
  353. short scale;
  354. int next_extension_word = 1;
  355. int type;
  356.  
  357. /* check for validity of extension word */
  358. if ((*extension & 0x0008) || !(*extension & 0x0030) || 
  359.     (*extension & 0x0007) == 0x0004 ||
  360.     ((*extension & 0x0007) >= 4 && (*extension & 0x0040)))
  361.   {
  362.   detected_illegal = TRUE;
  363.   return (0);
  364.   }
  365.  
  366. base_disp_size = (*extension & 0x0030) >> 4;
  367. outer_disp_size = (*extension & 0x0003);
  368.  
  369.  
  370. /* generate string for index register */
  371. strcpy (index_reg, reg_names [*extension >> 12]);
  372. if (*extension & 0x0800)
  373.   strcat (index_reg, ".L");
  374. else
  375.   strcat (index_reg, ".W");
  376. scale = 1 << ((*extension & 0x0600) >> 9);
  377. if (scale != 1)
  378.   {
  379.   sprintf (tmp_string, "*%d", scale);
  380.   strcat (index_reg, tmp_string);
  381.   }
  382.  
  383. /* generate string for base register */
  384. if (mode == 7)
  385.   {
  386.   /* PC memory indirect */
  387.   strcpy (base_reg, reg_names [PC]);
  388.   }
  389. else
  390.   strcpy (base_reg, reg_names [reg + 8]);
  391.  
  392. /* generate string for base displacement */
  393. switch (base_disp_size)
  394.   {
  395.   case 1: /* Null displacement */
  396.     strcpy (base_disp, "0");
  397.     break;
  398.   case 2: /* Word displacement */
  399.     if (mode == 7)                      /* PC relative */
  400.       {
  401.       if (pass2)
  402.         enter_ref (current_address + 2 + *(extension + next_extension_word++),
  403.                    NULL, ACC_UNKNOWN);
  404.       else
  405.         gen_label (base_disp, 
  406.                    current_address + 2 + *(extension + next_extension_word++),
  407.                    TRUE);
  408.       }
  409.     else
  410.       format_d (base_disp, *(extension + next_extension_word++), TRUE);
  411.     break;
  412.   case 3: /* Long displacement */
  413.     if (mode == 7)                      /* PC relative */
  414.       {
  415.       if (pass2)
  416.         enter_ref (current_address + 2 + 
  417.                    (*(extension + next_extension_word) << 16) +
  418.                     *(extension + next_extension_word + 1),
  419.                    NULL, ACC_UNKNOWN);
  420.       else
  421.         gen_label (base_disp, 
  422.                    current_address + 2 + 
  423.                    (*(extension + next_extension_word) << 16) +
  424.                     *(extension + next_extension_word + 1),
  425.                    TRUE);
  426.       }
  427.     else
  428.       format_ld (base_disp, (*(extension + next_extension_word) << 16) +
  429.                  *(extension + next_extension_word + 1), TRUE);
  430.     next_extension_word += 2;
  431.     break;
  432.   }
  433.  
  434. /* generate string for outer displacement */
  435. switch (outer_disp_size)
  436.   {
  437.   case 1: /* Null displacement */
  438.     strcpy (outer_disp, "0");
  439.     break;
  440.   case 2: /* Word displacement */
  441.     format_d (outer_disp, *(extension + next_extension_word++), TRUE);
  442.     break;
  443.   case 3: /* Long displacement */
  444.     format_ld (outer_disp, (*(extension + next_extension_word) << 16) +
  445.                *(extension + next_extension_word + 1), TRUE);
  446.     next_extension_word += 2;
  447.     break;
  448.   }
  449.  
  450. type = ((*extension & 0x00c0) >> 3) | (*extension & 0x0007);
  451. switch (type)
  452.   {
  453.   case 0x00: sprintf (to, "%s(%s,%s)", base_disp, base_reg, index_reg); break;
  454.   case 0x01:
  455.   case 0x02:
  456.   case 0x03: sprintf (to, "([%s,%s,%s],%s)", base_disp, base_reg, 
  457.                       index_reg, outer_disp); break;
  458.   case 0x05:
  459.   case 0x06:
  460.   case 0x07: sprintf (to, "([%s,%s],%s,%s)", base_disp, base_reg, 
  461.                    index_reg, outer_disp); break;
  462.   case 0x08: sprintf (to, "%s(%s)", base_disp, base_reg); break;
  463.   case 0x09:
  464.   case 0x0a:
  465.   case 0x0b: sprintf (to, "([%s,%s],%s)", base_disp, base_reg, outer_disp); break;
  466.  
  467.   /* base register suppressed */
  468.   case 0x10: sprintf (to, "%s(%s)", base_disp, index_reg); break;
  469.   case 0x11:
  470.   case 0x12:
  471.   case 0x13: sprintf (to, "([%s,%s],%s)", base_disp, index_reg, 
  472.                       outer_disp); break;
  473.   case 0x15:
  474.   case 0x16:
  475.   case 0x17: sprintf (to, "([%s],%s,%s)", base_disp, index_reg, 
  476.                       outer_disp); break;
  477.   case 0x18: sprintf (to, "%s", base_disp); break;
  478.   case 0x19:
  479.   case 0x1a:
  480.   case 0x1b: sprintf (to, "([%s],%s)", base_disp, outer_disp); break;
  481.  
  482.   default: fprintf (stderr, "INTERNAL ERROR: full_extension: illegal addressing mode\n");
  483.            fprintf (stderr, "    Current address is: %lx\n", current_address);
  484.   }
  485.  
  486. return (next_extension_word);
  487. }
  488.  
  489. /**************************************************************************/
  490.  
  491. void format_line_spaces (BOOL labeled, BOOL commented)
  492.  
  493. {
  494. register char *tmp;
  495. register char blank = ' ';
  496.  
  497. gen_label (instruction, current_address, labeled);
  498. for (tmp = instruction; *tmp != 0; tmp++);
  499. if (tmp != instruction)
  500.   /* a label has been generated */
  501.   *tmp++ = ' ';
  502. while (tmp - instruction < OPCODE_COL)
  503.   *tmp++ = blank;
  504. strcpy (tmp, opcode);
  505.  
  506. if (!(src [0] == 0 && dest [0] == 0))
  507.   {
  508.   while (*(++tmp));          /* scan to end of string */
  509.   while (tmp - instruction < PARAM_COL)
  510.     *tmp++ = blank;
  511.   if (dest [0] == 0)
  512.     strcpy (tmp, src);
  513.   else if (src [0] == 0)
  514.     strcpy (tmp, dest);
  515.   else
  516.     {
  517.     strcpy (tmp, src);
  518.     while (*(++tmp));         /* scan to end of string */
  519.     *tmp++ = ',';
  520.     strcpy (tmp, dest);
  521.     }
  522.   }
  523.  
  524. if (add_file_offset && commented)
  525.   {
  526.   while (*(++tmp));         /* scan to end of string */
  527.   while (tmp - instruction < COMMENT_COL)
  528.     *tmp++ = blank;
  529.   *tmp++ = ';';
  530.   *tmp++ = blank;
  531.   format_ld (tmp, current_address - first_address + 
  532.              *(hunk_offset + current_hunk), FALSE);
  533.   }
  534.  
  535. strcat (tmp, "\n");
  536. if (end_instr)
  537.   strcat (tmp, "\n");
  538. }
  539.  
  540. /**************************************************************************/
  541.  
  542. int gen_label (char *where_to, ULONG ref, BOOL anyway)
  543.  
  544. /* returns the access type for the reference, if none is found returns
  545.    NO_ACCESS */
  546. {
  547. char *label;
  548. UWORD access;
  549.  
  550. if (find_reference (ref, &label, &access))
  551.   {
  552.   if (label != 0)
  553.     strcpy (where_to, label);
  554.   else
  555.     {
  556.     *where_to++ = 'L';
  557.     format_ld_no_dollars (where_to, ref, FALSE);
  558.     }
  559.   return ((int)access);
  560.   }
  561. else if (anyway)
  562.   {
  563.   *where_to++ = 'L';
  564.   format_ld_no_dollars (where_to, ref, FALSE);
  565.   }
  566. else
  567.   *where_to = 0;
  568. return (NO_ACCESS);
  569. }
  570.  
  571. /**************************************************************************/
  572.  
  573. BOOL is_string (char *maybe_string, ULONG max_len)
  574.  
  575. {
  576. register unsigned char *tmp;
  577. char *last_char;
  578.  
  579. /* Strings must not cross label boundaries */
  580. last_char = maybe_string + max_len;
  581. tmp = (unsigned char*) maybe_string;
  582. while (*tmp != 0 && IS_VALID (*tmp))
  583.   tmp++;
  584. if (*tmp == 0 && tmp < (unsigned char*)last_char &&
  585.     (char*)tmp != maybe_string)    /* Don't let single 0 characters be */
  586.                                    /* disassembled as strings */
  587.   return (TRUE);
  588. return (FALSE);
  589. }
  590.  
  591. /**************************************************************************/
  592.  
  593. void put (char *string)
  594.  
  595. {
  596. #ifdef DEBUG
  597. if (out == NULL)
  598.   {
  599.   fprintf (stderr, "INTERNAL ERROR: put: Attempt to write to closed file\n");
  600.   ExitADis ();
  601.   }
  602. #endif
  603.  
  604. if (fputs (string, out) == EOF)
  605.   {
  606.   fprintf (stderr, "\nError writing output file\n");
  607.   ExitADis ();
  608.   }
  609. }
  610.  
  611. /**************************************************************************/
  612.  
  613. void mark_entry_illegal (int entry)
  614.  
  615. {
  616. struct opcode_entry *op;
  617.  
  618. op = &(opcode_table [entry]);
  619. op->handler = illegal;
  620. op->mnemonic = "ILLEGAL";
  621. op->modes = op->submodes = 0xff;
  622. }
  623.  
  624. /**************************************************************************/
  625.  
  626. char *cpstr (char *dest, char *src, int max_len)
  627.  
  628. /* returns NULL, if the whole string fitted into max_len characters.
  629.    Otherwise a pointer is to the first character in "src" is passed,
  630.    which didn't fit in */
  631. {
  632. register char *from,
  633.               *to;
  634. register BOOL last_was_printable;
  635. int chars_used = 0;
  636.  
  637. last_was_printable = FALSE;
  638.  
  639. for (from = src, to = dest; *from != 0 && chars_used < max_len; from++)
  640.   {
  641.   if (IS_PRINTABLE (((UBYTE)*from)))
  642.     {
  643.     if (!last_was_printable)
  644.       {
  645.       *to++ = '"';
  646.       last_was_printable = TRUE;
  647.       chars_used++;
  648.       }
  649.     *to++ = *from;
  650.     chars_used++;
  651.     }
  652.   else 
  653.     {
  654.     if (last_was_printable)
  655.       {
  656.       *to++ = '"';
  657.       *to++ = ',';
  658.       chars_used += 2;
  659.       last_was_printable = FALSE;
  660.       }
  661.     to = format_d (to, (short)((UBYTE)*from), FALSE);
  662.     chars_used = strlen (dest) + 1;
  663.     *to++ = ',';
  664.     }
  665.   }
  666. if (chars_used < max_len)
  667.   {
  668.   if (last_was_printable)
  669.     {
  670.     *to++ = '"';
  671.     *to++ = ',';
  672.     }
  673.   *to++ = '0';
  674.   *to = 0;
  675.   return (NULL);
  676.   }
  677. else
  678.   {
  679.   if (last_was_printable)
  680.     *to++ = '"';
  681.   else 
  682.     to--;
  683.   *to = 0;
  684.   return (from);
  685.   }
  686. }
  687.  
  688. /**************************************************************************/
  689.  
  690. void gen_xref (ULONG address)
  691.  
  692. {
  693. register char *tmp;
  694. register char blank = ' ';
  695.  
  696. tmp = instruction;
  697. while (tmp - instruction < OPCODE_COL)
  698.   *tmp++ = blank;
  699. strcpy (tmp, "XREF");
  700. while (*(++tmp));          /* scan to end of string */
  701.  
  702. while (tmp - instruction < PARAM_COL)
  703.   *tmp++ = blank;
  704.  
  705. gen_label (tmp, address, TRUE);
  706. strcat (tmp, "\n");
  707. put (instruction);
  708. }
  709.  
  710. /**************************************************************************/
  711.  
  712. void assign_label_names (void)
  713.  
  714. /**********************************************************************/
  715. /*   Assigns each label an ascending number instead of its address    */
  716. /**********************************************************************/
  717. {
  718. long label_count = 1;
  719. char label_name [20];
  720. UWORD access;
  721. char *old_name;
  722.  
  723. current_address = 0L;
  724. label_name [0] = 'L';
  725.  
  726. while ((current_address = next_reference (current_address, total_size, &access))
  727.                 != total_size)
  728.   {
  729.   find_reference (current_address, &old_name, &access);
  730.   if (old_name == NULL)
  731.     {
  732.     format_ld_no_dollars (label_name + 1, label_count++, FALSE);
  733.     enter_ref (current_address, label_name, access);
  734.     }
  735.   }
  736.  
  737. current_address = 0L;
  738. }
  739.